﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using log4net;
using log4net.Core;
using log4net.Repository.Hierarchy;
using log4net.Appender;
using log4net.Layout;
using log4net.Filter;
using log4net.Config;

namespace GrayParrot.Logging
{
    //public class Logger<T> where T : class
    //{
    //    private static readonly ILog log = LogManager.GetLogger(typeof(T));

    //    public static ILog Log
    //    {
    //        get { return log; }
    //    }

    //    static Logger()
    //    {
    //        XmlConfigurator.Configure();
    //    }
    //}

    public static class Logger   //<T> where T : class
    {
        private static string m_inputArguments = string.Empty;
        private static int m_loggerIdentifier = 0;

        public static string InputArguments
        {
            get { return log4net.LogicalThreadContext.Properties["InputArguments"].ToString(); }
            set 
            {
                log4net.LogicalThreadContext.Properties["InputArguments"] = value;
            }
        }

        public static int LoggerIdentifier
        {
            get { return (int)log4net.LogicalThreadContext.Properties["LoggerIdentifier"]; }
            set
            {
                log4net.LogicalThreadContext.Properties["LoggerIdentifier"] = value;
            }
        }

        //private static readonly ILog log = LogManager.GetLogger(typeof(T));

        //public static ILog Log
        //{
        //    get 
        //    {
        //        ILog log = LogManager.GetLogger(typeof(T));
        //        return log; 
        //    }
        //}

        public static ILog For<T>() where T : class
        {
            ILog log = LogManager.GetLogger(typeof(T));
            return log; 
        }

        public static ILog For<T>(int loggerIdentifier) where T : class
        {
            LoggerIdentifier = loggerIdentifier;

            ILog log = LogManager.GetLogger(typeof(T));
            return log;
        }

        public static ILog For(Type type)
        {
            ILog log = LogManager.GetLogger(type);
            return log;
        }

        static Logger()
        {
            XmlConfigurator.Configure();
        }

        public static IAppender CreateFileAppender(string path)
        {
            RollingFileAppender appender = new RollingFileAppender();
            appender.Name = "RollingFileAppender";
            appender.File = path;  // String.Format(@"c:\logs\{0}\{0}.log", appCode);
            appender.AppendToFile = false;
            appender.RollingStyle = RollingFileAppender.RollingMode.Size;
            appender.MaxSizeRollBackups = 10;
            appender.MaximumFileSize = "100MB";

            PatternLayout layout = new PatternLayout();
            layout.ConversionPattern = "%newline%date %-5level %logger – %message – %property%newline";
            layout.ActivateOptions();

            appender.Layout = layout;
            appender.ActivateOptions();

            return appender;
        }

        public static IAppender CreateConsoleAppender()
        {
            ConsoleAppender appender = new ConsoleAppender();
            appender.Name = "ConsoleAppender";
            PatternLayout layout = new PatternLayout();
            layout.ConversionPattern = "%newline%date %-5level %logger – %message – %property%newline";
            layout.ActivateOptions();

            appender.Layout = layout;
            appender.ActivateOptions();

            return appender;
        }

        public static IAppender CreateAdoNetAppender(string cs, string tableName)
        {
            AdoNetAppender appender = new AdoNetAppender();
            appender.Name = "AdoNetAppender";
            appender.BufferSize = 1;
            appender.ConnectionType = "System.Data.SqlClient.SqlConnection, System.Data, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
            appender.ConnectionString = cs;
            appender.CommandText = @"INSERT INTO " + tableName + " ([Date],[Thread],[Level],[Logger],[Message],[Exception]) VALUES (@date,@thread,@level,@logger,@message,@exception)";

            Log4NetExtensions.AddDateTimeParameterToAppender(appender, "date", "%date{yyyy'-'MM'-'dd HH':'mm':'ss'.'fff}");
            Log4NetExtensions.AddStringParameterToAppender(appender, "thread", 20, "%thread");
            Log4NetExtensions.AddStringParameterToAppender(appender, "level", 10, "%level");
            Log4NetExtensions.AddStringParameterToAppender(appender, "logger", 200, "%logger");
            //AddStringParameterToAppender(appender, "message", 1000, "%message%newline%property");
            Log4NetExtensions.AddStringParameterToAppender(appender, "message", 1000, "%message");
            Log4NetExtensions.AddErrorParameterToAppender(appender, "exception", 4000);
            appender.ActivateOptions();
            return appender;
        }

        public static void ConfigureWithFile(string path)
        {
            Hierarchy h = (Hierarchy)LogManager.GetRepository();
            h.Root.Level = Level.All;
            h.Root.AddAppender(CreateFileAppender(path));
            h.Configured = true;
        }

        public static void ConfigureWithDb(string cs, string tableName, bool onlyErrors)
        {
            Hierarchy h = (Hierarchy)LogManager.GetRepository();
            h.Root.Level = Level.All;

            IAppender ado = CreateAdoNetAppender(cs, tableName);
            h.Root.AddAppender(ado);
            if (onlyErrors)
            {
                var filter = new LevelRangeFilter();
                filter.LevelMin = Level.Error;
                ((AppenderSkeleton)ado).AddFilter(filter);
            }

            h.Configured = true;
        }
    }

    public static class Log4NetExtensions
    {
        public static void AddStringParameterToAppender(this log4net.Appender.AdoNetAppender appender, string paramName, int size, string conversionPattern)
        {
            AdoNetAppenderParameter param = new AdoNetAppenderParameter();
            param.ParameterName = paramName;
            param.DbType = System.Data.DbType.String;
            param.Size = size;
            param.Layout = new Layout2RawLayoutAdapter(new PatternLayout(conversionPattern));
            appender.AddParameter(param);
        }

        public static void AddDateTimeParameterToAppender(this log4net.Appender.AdoNetAppender appender, string paramName, string conversionPattern)
        {
            AdoNetAppenderParameter param = new AdoNetAppenderParameter();
            param.ParameterName = paramName;
            param.DbType = System.Data.DbType.DateTime;
            //param.Layout = new RawUtcTimeStampLayout();
            param.Layout = new Layout2RawLayoutAdapter(new PatternLayout(conversionPattern));
            appender.AddParameter(param);
        }

        public static void AddDateTimeParameterToAppender(this log4net.Appender.AdoNetAppender appender, string paramName)
        {
            AdoNetAppenderParameter param = new AdoNetAppenderParameter();
            param.ParameterName = paramName;
            param.DbType = System.Data.DbType.DateTime;
            param.Layout = new RawUtcTimeStampLayout();
            appender.AddParameter(param);
        }

        public static void AddErrorParameterToAppender(this log4net.Appender.AdoNetAppender appender, string paramName, int size)
        {
            AdoNetAppenderParameter param = new AdoNetAppenderParameter();
            param.ParameterName = paramName;
            param.DbType = System.Data.DbType.String;
            param.Size = size;
            param.Layout = new Layout2RawLayoutAdapter(new ExceptionLayout());
            appender.AddParameter(param);
        }
    }
}
